package demo.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import demo.Result;
import demo.dto.*;
import demo.entity.Company;
import demo.entity.Department;
import demo.entity.User;
import demo.entity.UserCompany;
import demo.service.CompanyService;
import demo.service.DepartmentService;
import demo.service.UserCompanyService;
import demo.service.UserService;
import demo.util.JwtUtil;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Encoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Date;

/**
 * 用户账号和公司注册 Controller
 *
 * @author 肖溥博文
 * @version 1.6
 */
@RestController
public class AccountController {
    @Autowired
    UserService userService;
    @Autowired
    CompanyService companyService;
    @Autowired
    UserCompanyService userCompanyService;
    @Autowired
    JwtUtil jwtUtil;
    @Autowired
    DepartmentService departmentService;

    /**
     * 登录
     *
     * @param loginDto 登录必要信息，必须包含 uid 和密码
     * @param response http response
     * @return 结果对象，包含 uid、姓名、公司 id、职位
     */
    @PostMapping("/login")
    public Result login(@Validated @RequestBody LoginDto loginDto,
                        HttpServletResponse response) {
        // Find the user out and then check the user's password.
        // If the user is not found, throw an exception.
        User user = userService.findUserByUid(loginDto.getUid());
        if (user == null ||!user.getPassword().equals(loginDto.getPassword())) {
            return Result.error("登录密码错误。");
        }

        // If userCompany is not found, create a userCompany object to
        // pass parameters to the front.
        Result result = userCompanyService.findLatestUserCompanyByUid(user.getUid());
        UserCompany userCompany = (UserCompany) result.getData();
        if (userCompany == null) {
            userCompany = new UserCompany();
        }

        String jwt = jwtUtil.generateToken(user.getUid());
        response.setHeader("Authorization", jwt);
        response.setHeader("Access-Control-Expose-Headers", "Authorization");

        // Use MapUtil.builder() to generate maps.
        // Do not miss .map() method.
        return Result.success("登录成功", MapUtil.builder()
            .put("uid", user.getUid())
            .put("userName", user.getUserName())
            .put("companyId", userCompany.getCompanyId())
            .put("position", userCompany.getPosition())
            .map()
        );
    }

    // The pages which you can only get access to
    // should be attributed with the annotation
    // @RequiresAuthentication.

    /**
     * 登出
     *
     * @return 结果对象
     */
    @GetMapping("/logout")
    public Result logout() {
        SecurityUtils.getSubject().logout();
        return Result.success("成功登出");
    }

    /**
     * 检测身份证号是否重复
     *
     * @param user 用户信息，必须包含身份证号
     * @return 结果对象
     */
    @PostMapping("/isCardIdExisted")
    public Result isCardIdExisted(@RequestBody User user) {
        String cardId = user.getCardId();
        if (userService.isCardIdExisted(cardId)) {
            return Result.error("身份证号重复");
        }
        return Result.success("身份证号未重复");
    }


    @Value("${file.filePath}")
    private String filePath;

    /**
     * ******测试上传头像功能
     *
     * @param file 头像文件
     * @return 结果对象
     * @throws IOException i/o 异常
     */
    @PostMapping("/testUploadAvatar")
    public Result testUploadAvatar(@RequestPart("file") MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return Result.error("没有上传头像");
        }

        UUID uuid = UUID.randomUUID();

        String avatarName = uuid.toString();
        String path = filePath + uuid.toString() + ".jpg";
        file.transferTo(new File(path));
        System.out.println(filePath + avatarName);

        return Result.success("test upload avatar", uuid.toString());
    }

    /**
     *  ***** 测试按文件名获取头像功能
     * @param requestStringDto 文件名
     * @param response Http Response
     * @return
     * @throws IOException
     */
    @PostMapping("/testDownloadAvatar")
    public byte[] testDownloadAvatar(@Validated @RequestBody RequestStringDto requestStringDto,
                                     HttpServletResponse response) throws IOException {
        String uid = requestStringDto.getString();
        String avatarName = filePath + uid + ".jpg";

        response.setContentType("image/jpeg");
        FileInputStream inputStream = new FileInputStream(avatarName);

        byte[] buffer = new byte[inputStream.available()];
        inputStream.read(buffer, 0, inputStream.available());
        return buffer;
    }

    /**
     *  ***** 测试按用户 id 获取头像功能
     * @param requestWithLongDto uid
     * @param response Http Response
     * @return
     * @throws IOException
     */
    @PostMapping("/getAvatar")
    public byte[] testDownloadAvatar(@Validated @RequestBody RequestWithLongDto requestWithLongDto,
                                     HttpServletResponse response) throws IOException {
        User user = userService.findUserByUid(requestWithLongDto.getId());
        String fileName;
        if (user.getAvatar() == null) {
            fileName = "default";
        } else {
            fileName = user.getAvatar();
        }
        String avatarName = filePath + fileName + ".jpg";

        response.setContentType("image/jpeg");
        FileInputStream inputStream = new FileInputStream(avatarName);

        byte[] buffer = new byte[inputStream.available()];
        inputStream.read(buffer, 0, inputStream.available());
        return buffer;
    }

    /**
     * 注册
     *
     * @param user     注册必要信息
     * @param response http response
     * @return 结果对象，包含 uid、姓名
     */
    @PostMapping("/register")
    public Result register(@Validated @RequestBody User user, HttpServletResponse response) throws IOException {

        if (isCardIdExisted(user).getCode() == 400) {
            return Result.error("账户创建失败，身份证号已经注册");
        }

        Result result = userService.add(user);
        user = (User) result.getData();

        String jwt = jwtUtil.generateToken(user.getUid());
        response.setHeader("Authorization", jwt);
        response.setHeader("Access-Control-Expose-Headers", "Authorization");

        return Result.success("注册成功，你的账号是 " + user.getUid(), MapUtil.builder()
            .put("uid", user.getUid())
            .put("userName", user.getUserName())
            .put("companyId", null)
            .put("position", null)
            .map()
        );
    }

    /**
     * 注册公司。注意：前端需要将返回的信息存入 session storage
     *
     * @param requestCompanyRegisterDto 注册公司的信息，必须包含公司注册人的 uid 和公司名
     * @return 结果对象，包含用户 session storage 需要存储的必要信息
     */
    @PostMapping("/companyRegister")
    public Result companyRegister(@Validated @RequestBody RequestCompanyRegisterDto requestCompanyRegisterDto, HttpServletResponse response) {
        Long uid = requestCompanyRegisterDto.getUid();
        User user = userService.findUserByUid(uid);
        if (user == null) {
            return Result.error("用户不存在，无法注册公司");
        }

        Result findUserCompanyResult = userCompanyService.findLatestUserCompanyByUid(uid);
        if (findUserCompanyResult.getCode() == 200) {
            return Result.error("用户在职，无法注册公司");
        }

        // 添加公司
        Company company = new Company();
        BeanUtil.copyProperties(requestCompanyRegisterDto, company);
        Result resultRegisterCompany = companyService.add(company);
        if (resultRegisterCompany.getCode() != 200) {
            return resultRegisterCompany;
        }

        company = (Company) resultRegisterCompany.getData();

        // 添加第一个部门
        String departmentName = requestCompanyRegisterDto.getFirstDepartmentName();
        if (StrUtil.isBlank(departmentName)) {
            departmentName = "人事部";
        }
        Result addDepartmentResult = departmentService.add(departmentName, company.getCompanyId());
        Department department = (Department) addDepartmentResult.getData();

        // 添加 HR 的工作经历
        UserCompany userCompany = new UserCompany();
        userCompany.setUid(uid);
        userCompany.setCompanyId(company.getCompanyId());
        userCompany.setDepartmentId(department.getDepartmentId());
        userCompany.setPosition("HR");
        userCompany.setBeginTime(new Date());
        userCompanyService.update(userCompany, true);

        String jwt = jwtUtil.generateToken(user.getUid());
        response.setHeader("Authorization", jwt);
        response.setHeader("Access-Control-Expose-Headers", "Authorization");

        return Result.success("公司创建成功", MapUtil.builder()
            .put("uid", user.getUid())
            .put("userName", user.getUserName())
            .put("companyId", company.getCompanyId())
            .put("position", "HR")
            .map()
        );
    }

    /**
     * 修改公司信息
     *
     * @param requestModifyCompanyDto 公司信息，必须包含 公司 id 和 公司名
     * @return 结果对象，若成功将包含最新的公司信息
     */
    @PostMapping("/modifyCompany")
    public Result modifyCompany(@Validated @RequestBody RequestModifyCompanyDto requestModifyCompanyDto) {
        Long companyId = requestModifyCompanyDto.getCompanyId();
        Result findCompanyResult = companyService.find(companyId);
        if (findCompanyResult.getCode() != 200) {
            return Result.error("公司不存在，无法修改公司数据");
        }

        Company company = (Company) findCompanyResult.getData();
        BeanUtil.copyProperties(requestModifyCompanyDto, company);
        return companyService.update(company);
    }

    /**
     * 验证两人是否在同一公司
     *
     * @param operator 操作人对象
     * @param user     用户对象
     * @return 结果对象
     */
    public Result validateIsInSameCompany(User operator, User user) {
        Long uidOperator = operator.getUid();
        Long uidUser = user.getUid();

        UserCompany userCompanyOperator = (UserCompany)
            userCompanyService.findLatestUserCompanyByUid(uidOperator).getData();
        UserCompany userCompanyUser = (UserCompany)
            userCompanyService.findLatestUserCompanyByUid(uidUser).getData();

        if (userCompanyOperator == null || userCompanyUser == null) {
            return Result.error("不存在用户，或两人不都在职");
        }

        if (userCompanyOperator.getCompanyId().equals(userCompanyUser.getCompanyId())) {
            return Result.success("两人同属同一公司");
        }

        StringBuilder stringBuilder = new StringBuilder(operator.getUserName());
        stringBuilder.append(" 没有操作 ").append(user.getUserName()).append(" 数据的权限。");
        return Result.error(stringBuilder.toString());
    }

    /**
     * 验证两人是否在同一公司
     *
     * @param uidOperator 操作人 id
     * @param uidUser     用户 id
     * @return 结果对象
     */
    public Result validateIsInSameCompany(Long uidOperator, Long uidUser) {
        UserCompany userCompanyOperator = (UserCompany)
            userCompanyService.findLatestUserCompanyByUid(uidOperator).getData();
        UserCompany userCompanyUser = (UserCompany)
            userCompanyService.findLatestUserCompanyByUid(uidUser).getData();

        if (userCompanyOperator == null || userCompanyUser == null) {
            return Result.error("不存在用户，或两人不都在职");
        }

        if (userCompanyOperator.getCompanyId().equals(userCompanyUser.getCompanyId())) {
            return Result.success("两人同属同一公司");
        }

        StringBuffer stringBuffer = new StringBuffer("用户 id 为 ");
        stringBuffer.append(uidOperator.toString()).append(" 的用户没有操作用户 id 为 ").append(uidOperator.toString()).append(" 的用户数据的权限。");
        return Result.error(stringBuffer.toString());
    }

    private class OutputStream {
    }
}
